package be.sc.classicnetwork.model;

import java.io.Serializable;
import java.util.Date;
import java.util.UUID;

import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.Transient;
import javax.persistence.Version;

import org.apache.log4j.Logger;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.validator.ClassValidator;
import org.hibernate.validator.InvalidValue;

/**
 * Super class for entities. Specifies an id and a version attribute for
 * optimistic locking purpose.
 */
@MappedSuperclass
public abstract class AbstractEntity implements Serializable {
	@Transient
	protected final Logger log = Logger.getLogger(this.getClass());

	/** Primary key */
	@Id
	@GeneratedValue(generator = "system-uuid")
	@GenericGenerator(name = "system-uuid", strategy = "uuid")
	private String id;

	/** Version attribute for optimistic locking */
	@Version
	private Integer version = 0;

	private Date createdDate;

	private Date lastSavedDate;

	private String createdBy;

	private UserInfo userInfo = new UserInfo();

	/**
	 * Creates a default AbstractEntity.
	 */
	public AbstractEntity() {
		super();
	}

	/**
	 * Checks this entity hasn't been saved yet.
	 */
	public boolean isNew() {
		return (id == null);
	}

	/**
	 * Generates a unique id.
	 * 
	 * @see UUID
	 */
	public void generateId() {
		this.id = UUID.randomUUID().toString();
	}

	/**
	 * Validate this entity with the annotated hibernate validators.
	 * 
	 * @throws IllegalStateException
	 *             if an attribute is invalide
	 */
	@SuppressWarnings("unchecked")
	public void validate() {
		ClassValidator classValidator = new ClassValidator(this.getClass());
		InvalidValue[] invalidValues = classValidator.getInvalidValues(this);
		if ((invalidValues != null) && (invalidValues.length > 0)) {
			throw new IllegalStateException(invalidValues[0].getMessage());
		}
	}

	/**
	 * Creates an AbstractEntity with the specified id.
	 * 
	 * @param id
	 */
	public AbstractEntity(String id) {
		this.id = id;
	}

	/**
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object anObject) {
		if (this.getClass().isInstance(anObject)) {
			AbstractEntity ae = (AbstractEntity) anObject;
			return (this.id == null || ae.getId() == null) ? super
					.equals(anObject) : (this.id.equals(ae.getId()));
		}
		return false;
	}

	/**
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		return (id == null) ? super.hashCode() : id.hashCode();
	}

	/**
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return String.valueOf(id);
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public Integer getVersion() {
		return version;
	}

	public void setVersion(Integer version) {
		this.version = version;
	}

	public Date getCreatedDate() {
		return createdDate;
	}

	public void setCreatedDate(Date createdDate) {
		this.createdDate = createdDate;
	}

	public Date getLastSavedDate() {
		return lastSavedDate;
	}

	public void setLastSavedDate(Date lastSavedDate) {
		this.lastSavedDate = lastSavedDate;
	}

	public String getCreatedBy() {
		return createdBy;
	}

	public void setCreatedBy(String createdBy) {
		this.createdBy = createdBy;
	}

	public UserInfo getUserInfo() {
		return userInfo;
	}

	public void setUserInfo(UserInfo userInfo) {
		this.userInfo = userInfo;
	}

}
